#include "media_sys.h"

int score = 0;  

// 定义暂停、重新开始和退出的标志变量
int is_paused = 0;
int restart = 0;
int game_thread_exit = 0;  // 新增退出标志
int game_thread_running = 0; // 新增标志，记录游戏线程是否正在运行

pthread_t game_thread;

bool Game(MEDIA_POI mp)//游戏总接口
{
    printf("启动游戏成功！\n");

    //显示游戏界面
    if(Show_Ui(mp,"/tmp/game_ui.bmp") == false)
    {
        printf("显示游戏界面失败！\n");
        return  false;
    }

    //游戏触摸屏控制
    if(Game_Touch_Ctrl(mp) == false)
    {
        printf("游戏触摸屏控制失败！\n");
        return false;
    }
    
    return true;
}

bool Game_Touch_Ctrl(MEDIA_POI mp)//游戏界面触摸控制
{
    // 初始化木板的位置和大小
    GameBeginArgs args = {250, 140, 80, 40, 40, 0xff0000, mp, 200, 400, 200, 20,&score};

    while(1)
    {
        //先获取点击的触摸坐标，再去判断坐标是哪个按钮的区间
        if(Get_Touch_Xy(mp) == false)
        {
            printf("读取触摸屏坐标失败！\n");
            return false;
        }

        if(mp->touch_x > 600 && mp->touch_x < 800 && mp->touch_y > 112 && mp->touch_y < 198) //开始
        {
            printf("开始 !\n");
            if (!game_thread_running) { // 检查游戏线程是否正在运行
                game_thread_exit = 0;  // 重置退出标志
                if (pthread_create(&game_thread, NULL, (void*)Game_Begin_Thread, (void*)&args) != 0) 
                {
                    perror("pthread_create");
                    return false;
                }
                game_thread_running = 1; // 标记游戏线程正在运行
            }
        }

        if(mp->touch_x > 600 && mp->touch_x < 800 && mp->touch_y > 189 && mp->touch_y < 280) //暂停&继续
        {
            printf("暂停&继续 !\n");
            is_paused = !is_paused; // 切换暂停状态
        }

        if(mp->touch_x > 600 && mp->touch_x < 800 && mp->touch_y > 280 && mp->touch_y < 367) //重新开始
        {
            printf("重新开始！\n");
            restart = 1; // 设置重新开始标志
        }

        if(mp->touch_x > 600 && mp->touch_x < 773 && mp->touch_y > 367 && mp->touch_y < 480) //退出
        {
            printf("退出游戏线程！\n");
            game_thread_exit = 1;  // 设置退出标志
            pthread_join(game_thread, NULL);  // 等待线程退出
            game_thread_running = 0; // 标记游戏线程已停止

            //显示主界面
            if(Show_Ui(mp,"/tmp/main_ui.bmp") == false)
            {
                printf("显示主界面失败！\n");
                return false;
            }
            printf("%d\n",game_thread_exit);
            mp->touch_x = -1;
            mp->touch_y = -1;
            
            break;
        }

        // 处理木板的移动
        if (mp->touch_x < 600 && is_paused == 0) {
            args.board_x = mp->touch_x - args.board_width / 2;
            // 限制木板的移动范围
            if (args.board_x < 0) {
                args.board_x = 0;
            } else if (args.board_x + args.board_width > 600) {
                args.board_x = 600 - args.board_width;
            }
        }
    }

    return true;
}

// 线程函数
void* Game_Begin_Thread(void* arg)
{
    GameBeginArgs* args = (GameBeginArgs*)arg;
    int lcd_x = args->lcd_x;
    int lcd_y = args->lcd_y;
    int x0 = args->x0;
    int y0 = args->y0;
    int r = args->r;
    int color = args->color;
    MEDIA_POI mp = args->mp;
    int board_x = args->board_x;
    int board_y = args->board_y;
    int board_width = args->board_width;
    int board_height = args->board_height;
    int *score = args->score; // 获取得分指针

    int fd = open(LCD_DEV_PATH, O_RDWR); // 修改为正确的设备路径
    if (fd == -1)
    {
        perror("open...");
        pthread_exit(NULL);
    }
    
    unsigned int * lcd_ptr = (int *)mmap(NULL, 800*480*4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (lcd_ptr == MAP_FAILED)
    {
        perror("mmap...");
        close(fd);
        pthread_exit(NULL);
    }

    // 创建双缓冲
    unsigned int * buffer = (unsigned int *)malloc(800*480*sizeof(unsigned int));
    if (buffer == NULL)
    {
        perror("malloc...");
        munmap(lcd_ptr, 800*480*4);
        close(fd);
        pthread_exit(NULL);
    }

    int x, y;
    int n = 20; 
    int m = 20;
    int collided = 0; // 新增标志，记录小球是否与木板碰撞
    int prev_x0 = x0;
    int prev_y0 = y0;
    int prev_board_x = board_x;

    while(!game_thread_exit)
    {
        if (restart) 
        {
            x0 = 80;
            y0 = 40;
            n = 20;
            m = 20;
            board_x = args->board_x;
            *score = 0; // 重置得分
            restart = 0; // 重置重新开始标志
            collided = 0; // 重置碰撞标志
            prev_x0 = x0;
            prev_y0 = y0;
            prev_board_x = board_x;
        }

        if (!is_paused) {
            // 只在位置变化时进行重绘
            if (x0 != prev_x0 || y0 != prev_y0 || board_x != prev_board_x) 
            {
                // 清空缓冲区
                for(y = 0; y < 480; y++)
                {
                    for(x = 0; x < 800; x++)
                    {
                        buffer[y*800 + x] = 0xffffff;
                    }
                }

                // 绘制小球
                for(y = 0; y < 480; y++)
                {
                    for(x = 0; x < 600; x++)
                    {
                        if((x - x0)*(x - x0) + (y - y0)*(y - y0) <= r*r)
                        {
                            buffer[y*800 + x] = color;
                        }
                    }
                }

                // 绘制木板
                for (y = board_y; y < board_y + board_height; y++) 
                {
                    for (x = board_x; x < board_x + board_width; x++) 
                    {
                        buffer[y*800 + x] = 0x0000ff; // 蓝色
                    }
                }

                // 绘制按钮到缓冲区
                if (!draw_buttons_to_buffer(mp, buffer)) 
                {
                    printf("绘制按钮到缓冲区失败！\n");
                }

                // 将缓冲区内容复制到屏幕
                memcpy(lcd_ptr, buffer, 800*480*sizeof(unsigned int));

                // 显示得分
                char score_str[20];
                sprintf(score_str, "%d", *score);
                if (!Show_String(mp, score_str, 700, 50)) 
                {
                    printf("显示得分失败！\n");
                }

                prev_x0 = x0;
                prev_y0 = y0;
                prev_board_x = board_x;
            }

            // 更新木板的位置
            board_x = args->board_x;

            // 检测小球与木板的碰撞
            if (y0 + r >= board_y && x0 >= board_x && x0 <= board_x + board_width) 
            {
                if (!collided) {
                    n = -n; // 只有在首次碰撞时反转垂直速度
                    *score += 5; // 增加得分
                    collided = 1; // 标记为已碰撞
                }
            } else {
                collided = 0; // 小球离开木板，重置碰撞标志
            }

            x0 += m;
            y0 += n;

            if ((y0 + r) >= 480 || y0 < r)
            {
                n = -n;
            }
            if ((x0 + r) >= 600 || x0 < r)
            {
                m = -m;
            }
        }

        //usleep(5000); // 适当延迟，避免CPU占用过高
    }

    free(buffer);

    if (munmap(lcd_ptr, 800*480*4) == -1)
    {
        perror("munmap...");
    }

    if (close(fd) == -1)
    {
        perror("close...");
    }

    pthread_exit(NULL);
}


bool draw_buttons_to_buffer(MEDIA_POI mp, unsigned int * buffer) 
{
    if (!show_bmp_to_buffer(mp, buffer, "/tmp/game_use/score.bmp", 600, 20)) 
    {
        return false;
    }
    if (!show_bmp_to_buffer(mp, buffer, "/tmp/game_use/start_game.bmp", 600, 112)) 
    {
        return false;
    }
    if (!show_bmp_to_buffer(mp, buffer, "/tmp/game_use/pause_game.bmp", 600, 196))
    {
        return false;
    }
    if (!show_bmp_to_buffer(mp, buffer, "/tmp/game_use/restart_game.bmp", 600, 280)) 
    {
        return false;
    }
    if (!show_bmp_to_buffer(mp, buffer, "/tmp/game_use/exit_game.bmp", 600, 360)) {
        return false;
    }
    return true;
}

bool show_bmp_to_buffer(MEDIA_POI mp, unsigned int * buffer, const char *path, int x, int y) 
{
    // 这里需要实现将 BMP 图片绘制到缓冲区的逻辑
    // 假设已经有一个函数可以读取 BMP 文件并返回像素数据
    unsigned int *bmp_data = read_bmp_file(path);
    if (bmp_data == NULL) {
        return false;
    }

    // 获取 BMP 图片的宽度和高度
    int bmp_width = get_bmp_width(path);
    int bmp_height = get_bmp_height(path);

    // 将 BMP 数据复制到缓冲区，从底部开始复制
    for (int i = 0; i < bmp_height; i++) {
        for (int j = 0; j < bmp_width; j++) {
            if (y + (bmp_height - 1 - i) < 480 && x + j < 800) 
            {
                buffer[(y + (bmp_height - 1 - i)) * 800 + (x + j)] = bmp_data[i * bmp_width + j];
            }
        }
    }

    free(bmp_data);
    return true;
}


// 读取 BMP 文件并返回像素数据
unsigned int *read_bmp_file(const char *path) {
    int fd = open(path, O_RDONLY);
    if (fd == -1) {
        perror("open");
        return NULL;
    }

    // 获取图片的宽度和高度
    int bmp_w, bmp_h;
    if (lseek(fd, 18, SEEK_SET) == -1) {
        perror("lseek 18");
        close(fd);
        return NULL;
    }

    if (read(fd, &bmp_w, sizeof(int)) == -1) {
        perror("read bmp_w");
        close(fd);
        return NULL;
    }

    if (read(fd, &bmp_h, sizeof(int)) == -1) {
        perror("read bmp_h");
        close(fd);
        return NULL;
    }

    int skip = 0;
    if (bmp_w * 3 % 4 != 0) {
        skip = 4 - (bmp_w * 3 % 4);
    }

    int bmp_size = bmp_w * bmp_h * 3 + bmp_h * skip;
    unsigned char *rgb = (unsigned char *)malloc(bmp_size);
    if (rgb == NULL) {
        perror("malloc");
        close(fd);
        return NULL;
    }

    // 读取图片的像素点
    if (lseek(fd, 54, SEEK_SET) == -1) {
        perror("lseek 54");
        free(rgb);
        close(fd);
        return NULL;
    }

    if (read(fd, rgb, bmp_size) == -1) {
        perror("read bmp rgb");
        free(rgb);
        close(fd);
        return NULL;
    }

    // 将 BGR 格式转换为 RGB 格式，并存储为 unsigned int
    unsigned int *bmp_data = (unsigned int *)malloc(bmp_w * bmp_h * sizeof(unsigned int));
    if (bmp_data == NULL) {
        perror("malloc");
        free(rgb);
        close(fd);
        return NULL;
    }

    for (int y = 0, n = 0; y < bmp_h; y++) {
        for (int x = 0; x < bmp_w; x++, n += 3) {
            bmp_data[y * bmp_w + x] = rgb[n] << 0 | rgb[n + 1] << 8 | rgb[n + 2] << 16;
        }
        n += skip;
    }

    free(rgb);
    close(fd);
    return bmp_data;
}

// 获取 BMP 图片的宽度
int get_bmp_width(const char *path) {
    int fd = open(path, O_RDONLY);
    if (fd == -1) {
        perror("open");
        return -1;
    }

    int bmp_w;
    if (lseek(fd, 18, SEEK_SET) == -1) {
        perror("lseek 18");
        close(fd);
        return -1;
    }

    if (read(fd, &bmp_w, sizeof(int)) == -1) {
        perror("read bmp_w");
        close(fd);
        return -1;
    }

    close(fd);
    return bmp_w;
}

// 获取 BMP 图片的高度
int get_bmp_height(const char *path) {
    int fd = open(path, O_RDONLY);
    if (fd == -1) {
        perror("open");
        return -1;
    }

    int bmp_h;
    if (lseek(fd, 22, SEEK_SET) == -1) {
        perror("lseek 22");
        close(fd);
        return -1;
    }

    if (read(fd, &bmp_h, sizeof(int)) == -1) {
        perror("read bmp_h");
        close(fd);
        return -1;
    }

    close(fd);
    return bmp_h;
}

bool Show_String(MEDIA_POI mp, char *str, int x, int y)
{
    for (int i = 0; str[i] != '\0'; i++) {
        if (!Char_Show(str[i], x + i * 8, y)) 
        {
            return false;
        }
    }
    return true;
}